<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>K8s Pod 日志查看器</title>
    <script src="https://cdn.tailwindcss.com"></script>
    <link href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css" rel="stylesheet">
    <script>
        tailwind.config = {
            theme: {
                extend: {
                    colors: {
                        primary: '#3B82F6',
                        secondary: '#10B981',
                        dark: '#1E293B',
                        light: '#F8FAFC'
                    },
                    fontFamily: {
                        sans: ['Inter', 'system-ui', 'sans-serif'],
                    },
                }
            }
        }
    </script>
    <style type="text/tailwindcss">
        @layer utilities {
            .content-auto {
                content-visibility: auto;
            }
            .log-container {
                height: 500px;
                overflow-y: auto;
                font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
            }
            .shadow-custom {
                box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
            }
            .fade-in {
                animation: fadeIn 0.3s ease-in-out;
            }
            @keyframes fadeIn {
                from { opacity: 0; }
                to { opacity: 1; }
            }
        }
    </style>
</head>
<body class="bg-gray-50 min-h-screen">
    <div class="container mx-auto px-4 py-8 max-w-6xl">
        <header class="mb-8">
            <h1 class="text-[clamp(1.5rem,3vw,2.5rem)] font-bold text-dark mb-2">
                <i class="fa fa-kubernetes text-primary mr-2"></i>K8s Pod 日志查看器
            </h1>
            <p class="text-gray-600">上传kubeconfig，选择Pod查看实时日志</p>
        </header>

        <!-- 上传kubeconfig部分 -->
        <div class="bg-white rounded-lg shadow-custom p-6 mb-6 transition-all duration-300 hover:shadow-lg">
            <h2 class="text-xl font-semibold mb-4 text-dark">
                <i class="fa fa-upload text-primary mr-2"></i>上传Kubeconfig
            </h2>
            <div class="flex flex-col md:flex-row gap-4">
                <div class="flex-1">
                    <label for="kubeconfigFile" class="block text-sm font-medium text-gray-700 mb-1">
                        支持格式: .kubeconfig, .yml, .yaml, .conf, .txt 或无扩展名
                    </label>
                    <input type="file" id="kubeconfigFile" 
                           accept=".kubeconfig,.yml,.yaml,.conf,.txt,config" 
                           class="block w-full text-sm text-gray-500
                                  file:mr-4 file:py-2 file:px-4
                                  file:rounded-lg file:border-0
                                  file:text-sm file:font-medium
                                  file:bg-primary file:text-white
                                  hover:file:bg-primary/90 cursor-pointer" />
                </div>
                <button id="uploadBtn" class="bg-primary hover:bg-primary/90 text-white font-medium py-2 px-6 rounded-lg transition-all duration-200 flex items-center justify-center">
                    <i class="fa fa-save mr-2"></i>上传配置
                </button>
            </div>
            <div id="uploadStatus" class="mt-4 hidden"></div>
        </div>

        <!-- 选择部分 -->
        <div id="selectionSection" class="bg-white rounded-lg shadow-custom p-6 mb-6 hidden fade-in">
            <h2 class="text-xl font-semibold mb-4 text-dark">
                <i class="fa fa-list-alt text-primary mr-2"></i>选择资源
            </h2>
            <div class="grid grid-cols-1 md:grid-cols-3 gap-4">
                <!-- 命名空间选择 -->
                <div>
                    <label for="namespaceSelect" class="block text-sm font-medium text-gray-700 mb-1">命名空间</label>
                    <div class="relative">
                        <select id="namespaceSelect" class="block w-full pl-3 pr-10 py-2 text-base border-gray-300 focus:outline-none focus:ring-primary focus:border-primary sm:text-sm rounded-lg appearance-none bg-white">
                            <option value="">加载中...</option>
                        </select>
                        <div class="pointer-events-none absolute inset-y-0 right-0 flex items-center px-2 text-gray-700">
                            <i class="fa fa-chevron-down text-xs"></i>
                        </div>
                    </div>
                </div>

                <!-- Pod选择 -->
                <div>
                    <label for="podSelect" class="block text-sm font-medium text-gray-700 mb-1">Pod名称</label>
                    <div class="relative">
                        <select id="podSelect" disabled class="block w-full pl-3 pr-10 py-2 text-base border-gray-300 bg-gray-100 sm:text-sm rounded-lg appearance-none">
                            <option value="">请先选择命名空间</option>
                        </select>
                        <div class="pointer-events-none absolute inset-y-0 right-0 flex items-center px-2 text-gray-700">
                            <i class="fa fa-chevron-down text-xs"></i>
                        </div>
                    </div>
                </div>

                <!-- 容器选择 -->
                <div>
                    <label for="containerSelect" class="block text-sm font-medium text-gray-700 mb-1">容器名称</label>
                    <div class="relative">
                        <select id="containerSelect" disabled class="block w-full pl-3 pr-10 py-2 text-base border-gray-300 bg-gray-100 sm:text-sm rounded-lg appearance-none">
                            <option value="">请先选择Pod</option>
                        </select>
                        <div class="pointer-events-none absolute inset-y-0 right-0 flex items-center px-2 text-gray-700">
                            <i class="fa fa-chevron-down text-xs"></i>
                        </div>
                    </div>
                </div>
            </div>

            <div class="mt-4 flex justify-end">
                <button id="viewLogBtn" disabled class="bg-secondary hover:bg-secondary/90 text-white font-medium py-2 px-6 rounded-lg transition-all duration-200 flex items-center">
                    <i class="fa fa-eye mr-2"></i>查看日志
                </button>
            </div>
        </div>

        <!-- 日志显示部分 -->
        <div id="logSection" class="bg-white rounded-lg shadow-custom p-6 hidden fade-in">
            <div class="flex justify-between items-center mb-4">
                <h2 class="text-xl font-semibold text-dark">
                    <i class="fa fa-terminal text-primary mr-2"></i>实时日志
                </h2>
                <div class="flex gap-2">
                    <button id="clearLogBtn" class="bg-gray-200 hover:bg-gray-300 text-gray-700 font-medium py-1 px-4 rounded-lg transition-all duration-200 text-sm">
                        <i class="fa fa-trash mr-1"></i>清空
                    </button>
                    <button id="stopLogBtn" class="bg-red-500 hover:bg-red-600 text-white font-medium py-1 px-4 rounded-lg transition-all duration-200 text-sm">
                        <i class="fa fa-stop mr-1"></i>停止
                    </button>
                </div>
            </div>
            <div id="logStatus" class="mb-4 text-sm text-gray-600"></div>
            <div id="logContainer" class="bg-gray-900 text-gray-100 p-4 rounded-lg log-container text-sm"></div>
        </div>
    </div>

    <script>
        // 全局变量
        let sessionID = null;
        let ws = null;

        // DOM元素
        const kubeconfigFile = document.getElementById('kubeconfigFile');
        const uploadBtn = document.getElementById('uploadBtn');
        const uploadStatus = document.getElementById('uploadStatus');
        const selectionSection = document.getElementById('selectionSection');
        const namespaceSelect = document.getElementById('namespaceSelect');
        const podSelect = document.getElementById('podSelect');
        const containerSelect = document.getElementById('containerSelect');
        const viewLogBtn = document.getElementById('viewLogBtn');
        const logSection = document.getElementById('logSection');
        const logContainer = document.getElementById('logContainer');
        const logStatus = document.getElementById('logStatus');
        const clearLogBtn = document.getElementById('clearLogBtn');
        const stopLogBtn = document.getElementById('stopLogBtn');

        // 上传kubeconfig
        uploadBtn.addEventListener('click', async () => {
            // 重置状态
            showStatus(uploadStatus, '', '');
            uploadStatus.classList.add('hidden');

            // 检查是否选择文件
            if (!kubeconfigFile.files || kubeconfigFile.files.length === 0) {
                showStatus(uploadStatus, '请选择kubeconfig文件', 'error');
                return;
            }

            const file = kubeconfigFile.files[0];
            
            // 自定义文件类型验证
            const allowedExtensions = [
                'kubeconfig', 'yml', 'yaml', 'conf', 'txt', 
                'config', // 常见的无扩展名kubeconfig文件名
                '' // 允许无扩展名文件
            ];
            const fileName = file.name.toLowerCase();
            const fileExt = fileName.includes('.') 
                ? fileName.split('.').pop() 
                : fileName; // 处理无扩展名的文件
            
            if (!allowedExtensions.includes(fileExt)) {
                showStatus(uploadStatus, 
                    `不支持的文件类型。支持的格式: .kubeconfig, .yml, .yaml, .conf, .txt 或无扩展名的config文件`, 
                    'error');
                return;
            }

            // 准备表单数据
            const formData = new FormData();
            formData.append('kubeconfig', file);

            try {
                showStatus(uploadStatus, '正在上传...', 'info');
                
                const response = await fetch('/upload-kubeconfig', {
                    method: 'POST',
                    body: formData,
                    // 不设置Content-Type，让浏览器自动处理
                });

                const result = await response.json();
                
                if (response.ok) {
                    sessionID = result.sessionID;
                    showStatus(uploadStatus, result.message, 'success');
                    
                    // 显示选择区域并加载命名空间
                    selectionSection.classList.remove('hidden');
                    loadNamespaces();
                } else {
                    showStatus(uploadStatus, result.message || '上传失败', 'error');
                }
            } catch (error) {
                showStatus(uploadStatus, '上传失败: ' + error.message, 'error');
                console.error('上传错误:', error);
            }
        });

        // 加载命名空间
        async function loadNamespaces() {
            try {
                namespaceSelect.innerHTML = '<option value="">加载中...</option>';
                
                const response = await fetch(`/namespaces?sessionID=${sessionID}`);
                const namespaces = await response.json();
                
                if (response.ok) {
                    namespaceSelect.innerHTML = '<option value="">请选择命名空间</option>';
                    namespaces.forEach(ns => {
                        const option = document.createElement('option');
                        option.value = ns;
                        option.textContent = ns;
                        namespaceSelect.appendChild(option);
                    });
                } else {
                    namespaceSelect.innerHTML = '<option value="">加载失败</option>';
                    showStatus(uploadStatus, namespaces.message || '加载命名空间失败', 'error');
                }
            } catch (error) {
                namespaceSelect.innerHTML = '<option value="">加载失败</option>';
                showStatus(uploadStatus, '加载命名空间失败: ' + error.message, 'error');
                console.error('加载命名空间错误:', error);
            }
        }

        // 命名空间变化时加载Pod
        namespaceSelect.addEventListener('change', () => {
            const namespace = namespaceSelect.value;
            if (namespace) {
                loadPods(namespace);
                podSelect.disabled = false;
                podSelect.classList.remove('bg-gray-100');
                podSelect.classList.add('bg-white');
                containerSelect.disabled = true;
                containerSelect.classList.add('bg-gray-100');
                containerSelect.classList.remove('bg-white');
                viewLogBtn.disabled = true;
            } else {
                podSelect.innerHTML = '<option value="">请先选择命名空间</option>';
                podSelect.disabled = true;
                podSelect.classList.add('bg-gray-100');
                podSelect.classList.remove('bg-white');
                containerSelect.innerHTML = '<option value="">请先选择Pod</option>';
                containerSelect.disabled = true;
                viewLogBtn.disabled = true;
            }
        });

        // 加载Pod列表
        async function loadPods(namespace) {
            try {
                podSelect.innerHTML = '<option value="">加载中...</option>';
                
                const response = await fetch(`/pods?sessionID=${sessionID}&namespace=${namespace}`);
                const pods = await response.json();
                
                if (response.ok) {
                    podSelect.innerHTML = '<option value="">请选择Pod</option>';
                    pods.forEach(pod => {
                        const option = document.createElement('option');
                        option.value = pod;
                        option.textContent = pod;
                        podSelect.appendChild(option);
                    });
                } else {
                    podSelect.innerHTML = '<option value="">加载失败</option>';
                    showStatus(uploadStatus, pods.message || '加载Pod失败', 'error');
                }
            } catch (error) {
                podSelect.innerHTML = '<option value="">加载失败</option>';
                showStatus(uploadStatus, '加载Pod失败: ' + error.message, 'error');
                console.error('加载Pod错误:', error);
            }
        }

        // Pod变化时加载容器
        podSelect.addEventListener('change', () => {
            const namespace = namespaceSelect.value;
            const podName = podSelect.value;
            
            if (namespace && podName) {
                loadContainers(namespace, podName);
                containerSelect.disabled = false;
                containerSelect.classList.remove('bg-gray-100');
                containerSelect.classList.add('bg-white');
                viewLogBtn.disabled = true;
            } else {
                containerSelect.innerHTML = '<option value="">请先选择Pod</option>';
                containerSelect.disabled = true;
                containerSelect.classList.add('bg-gray-100');
                containerSelect.classList.remove('bg-white');
                viewLogBtn.disabled = true;
            }
        });

        // 加载容器列表
        async function loadContainers(namespace, podName) {
            try {
                containerSelect.innerHTML = '<option value="">加载中...</option>';
                
                const response = await fetch(`/containers?sessionID=${sessionID}&namespace=${namespace}&podName=${podName}`);
                const containers = await response.json();
                
                if (response.ok) {
                    containerSelect.innerHTML = '<option value="">请选择容器（可选）</option>';
                    containers.forEach(container => {
                        const option = document.createElement('option');
                        option.value = container;
                        option.textContent = container;
                        containerSelect.appendChild(option);
                    });
                    viewLogBtn.disabled = false;
                } else {
                    containerSelect.innerHTML = '<option value="">加载失败</option>';
                    showStatus(uploadStatus, containers.message || '加载容器失败', 'error');
                    viewLogBtn.disabled = true;
                }
            } catch (error) {
                containerSelect.innerHTML = '<option value="">加载失败</option>';
                showStatus(uploadStatus, '加载容器失败: ' + error.message, 'error');
                console.error('加载容器错误:', error);
                viewLogBtn.disabled = true;
            }
        }

        // 查看日志
        viewLogBtn.addEventListener('click', () => {
            const namespace = namespaceSelect.value;
            const podName = podSelect.value;
            const container = containerSelect.value;
            
            if (!namespace || !podName) {
                alert('请选择命名空间和Pod');
                return;
            }

            // 关闭现有连接
            if (ws) {
                ws.close();
            }

            // 显示日志区域
            logSection.classList.remove('hidden');
            logContainer.innerHTML = '';
            showLogStatus(`正在连接到 Pod ${podName} 的日志流...`);

            // 连接WebSocket
            const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
            const wsUrl = `${protocol}//${window.location.host}/pod/log/stream`;
            ws = new WebSocket(wsUrl);

            // WebSocket事件
            ws.onopen = () => {
                showLogStatus(`已连接到 Pod ${podName} 的日志流`);
                // 发送日志请求
                ws.send(JSON.stringify({
                    namespace: namespace,
                    podName: podName,
                    container: container,
                    tailLines: 100,
                    sessionID: sessionID
                }));
            };

            ws.onmessage = (event) => {
                try {
                    // 尝试解析为JSON消息
                    const data = JSON.parse(event.data);
                    if (data.type === 'error') {
                        addLog(`[错误] ${data.message}`, 'red');
                    } else if (data.type === 'init') {
                        addLog(`[信息] ${data.message}`, 'green');
                    } else if (data.type === 'close') {
                        addLog(`[信息] ${data.message}`, 'yellow');
                    }
                } catch (e) {
                    // 非JSON消息，视为日志内容
                    addLog(event.data);
                }
            };

            ws.onerror = (error) => {
                showLogStatus(`连接错误: ${error.message || '未知错误'}`, 'error');
                addLog(`[错误] 日志流连接错误: ${error.message || '未知错误'}`, 'red');
            };

            ws.onclose = (event) => {
                let closeMsg = '日志流已关闭';
                if (event.code !== 1000) {
                    closeMsg += ` (代码: ${event.code}, 原因: ${event.reason || '未知'})`;
                }
                showLogStatus(closeMsg, 'closed');
                addLog(`[信息] ${closeMsg}`, 'yellow');
                ws = null;
            };
        });

        // 清空日志
        clearLogBtn.addEventListener('click', () => {
            logContainer.innerHTML = '';
        });

        // 停止日志
        stopLogBtn.addEventListener('click', () => {
            if (ws) {
                ws.close(1000, '用户主动关闭');
                ws = null;
                showLogStatus('日志流已手动关闭', 'closed');
                addLog('[信息] 日志流已手动关闭', 'yellow');
            }
        });

        // 工具函数: 显示状态消息
        function showStatus(element, message, type) {
            element.textContent = message;
            element.classList.remove('hidden', 'text-green-600', 'text-red-600', 'text-blue-600', 'bg-green-50', 'bg-red-50', 'bg-blue-50', 'p-2', 'rounded');
            
            if (message) {
                element.classList.remove('hidden');
                if (type === 'success') {
                    element.classList.add('text-green-600', 'bg-green-50', 'p-2', 'rounded');
                } else if (type === 'error') {
                    element.classList.add('text-red-600', 'bg-red-50', 'p-2', 'rounded');
                } else if (type === 'info') {
                    element.classList.add('text-blue-600', 'bg-blue-50', 'p-2', 'rounded');
                }
            }
        }

        // 工具函数: 显示日志状态
        function showLogStatus(message, status = 'active') {
            logStatus.textContent = message;
            logStatus.classList.remove('text-green-600', 'text-red-600', 'text-blue-600', 'text-gray-600');
            
            if (status === 'active') {
                logStatus.classList.add('text-blue-600');
            } else if (status === 'error') {
                logStatus.classList.add('text-red-600');
            } else if (status === 'closed') {
                logStatus.classList.add('text-gray-600');
            } else {
                logStatus.classList.add('text-green-600');
            }
        }

        // 工具函数: 添加日志到容器
        function addLog(text, color = 'white') {
            const logLine = document.createElement('div');
            logLine.textContent = text;
            
            // 设置颜色
            if (color === 'red') {
                logLine.classList.add('text-red-300');
            } else if (color === 'green') {
                logLine.classList.add('text-green-300');
            } else if (color === 'yellow') {
                logLine.classList.add('text-yellow-300');
            }
            
            logContainer.appendChild(logLine);
            // 滚动到底部
            logContainer.scrollTop = logContainer.scrollHeight;
        }

        // 页面关闭时清理WebSocket连接
        window.addEventListener('beforeunload', () => {
            if (ws) {
                ws.close(1000, '页面关闭');
            }
        });
    </script>
</body>
</html>

